#include "irs2975c_flash.h"
#define DEBUG 0

int I2C_READ(RX_SPI_FH *rsf, int reg, unsigned short *data)
{
	int ret = sensor_read(rsf->sd, reg, data);
	if (ret) {
		printk(KERN_ERR "i2c read data=0x%x error, ret=%d!\n", reg,
		       ret);
		return -2;
	}
	return ret;
}
extern int cci_read_a0_d16(struct v4l2_subdev *sd, unsigned short *value);
int I2C_BURST_READ(RX_SPI_FH *rsf, int reg, unsigned short *data, int len)
{
	int ret = 0;
	int i;
	ret = cci_read_a16_d16(rsf->sd, reg, data++);
	for (i = 0; i < (len - 1); i++) {
		ret = cci_read_a0_d16(rsf->sd, data);
		//printk(KERN_INFO "I2C_BURST_READ %d====0x%x!\n", i, *data);
		data++;
	}
	return 0;
}

int I2C_WRITE(RX_SPI_FH *rsf, int reg, int data)
{
	int ret = sensor_write(rsf->sd, reg, data);
	if (ret) {
		return ret;
	}
	return 0;
}

int I2C_BURST_WRITE(RX_SPI_FH *rsf, unsigned short addr, unsigned char *data,
		    int len)
{
	unsigned short val;
	int size = (len % 2) ? len - 1 : len;
	int ret = cci_write_a16_d8_continuous_helper(rsf->sd, addr, data, size);
	if (ret) {
		printk(KERN_ERR "I2C_BURST_WRITE error, ret=%d!\n", ret);
		return -1;
	}
	if ((len % 2) != 0) {
		val = *(data + len - 1);
		//printk(KERN_ERR "last val=0x%x!\n", val);
		ret = cci_write_a16_d8_continuous_helper(
			rsf->sd, addr + len / 2, (unsigned char *)&val, 2);
		if (ret) {
			printk(KERN_ERR "I2C_BURST_WRITE error, ret=%d!\n",
			       ret);
			return -1;
		}
	}
	return 0;
}

static int _pll_power_up(RX_SPI_FH *rsf);
static int _config_spi(RX_SPI_FH *rsf);
static int _setup_spi(RX_SPI_FH *rsf);
static int _spi_command_finished(RX_SPI_FH *rsf);
static void _flash_write_enable(RX_SPI_FH *rsf);
static bool _is_flash_busy(RX_SPI_FH *rsf);
static int flash_read(RX_SPI_FH *rsf, uint32_t start_addr,
		      uint32_t num_of_bytes, uint8_t *buf);
static int _read_single_buffer(RX_SPI_FH *rsf, uint32_t start_address,
			       uint32_t num_of_bytes, uint8_t *buf);
static int _write_single_page(RX_SPI_FH *rsf, uint32_t page_address,
			      uint8_t *data_bytes, uint32_t num_of_bytes);

static void words_to_bytes(uint16_t *input_words, uint8_t *output_bytes,
			   int num_of_bytes)
{
	int num_of_words = num_of_bytes / 2;
	int last_word_incomplete = num_of_bytes % 2;
	int i;

	for (i = 0; i < num_of_words; i++) {
		output_bytes[2 * i] = (uint8_t)(input_words[i] >> 8);
		output_bytes[2 * i + 1] = (uint8_t)(input_words[i] & 0xFF);
	}
	if (last_word_incomplete) {
		output_bytes[num_of_bytes - 1] = input_words[i] >> 8;
	}
}

static int _pll_power_up(RX_SPI_FH *rsf)
{
	int ret = -1;
	bool pll_running = false;
	uint16_t cmc_val = 0x55;
	ktime_t start_time;
	//printk(KERN_INFO "start power up\n");
	if (24000000 == rsf->f_ref) {
		ret = I2C_WRITE(rsf, PLL_SYSLUT_CFG0_ADDR, 0x16A1);
		ret |= I2C_WRITE(rsf, PLL_SYSLUT_CFG1_ADDR, 0x5555);
		ret |= I2C_WRITE(rsf, PLL_SYSLUT_CFG2_ADDR, 0x0005);
		ret |= I2C_WRITE(rsf, PLL_SYSLUT_CFG3_ADDR, 0x0000);
		ret |= I2C_WRITE(rsf, PLL_SYSLUT_CFG4_ADDR, 0x04D0);
		ret |= I2C_WRITE(rsf, PLL_SYSLUT_CFG5_ADDR, 0x0000);
		ret |= I2C_WRITE(rsf, PLL_SYSLUT_CFG6_ADDR, 0x000F);
	} else {
		printk(KERN_ERR
		       "No PLL settings available for the given reference frequency of "
		       "f_ref: %d\n",
		       rsf->f_ref);
	}

	ret |= I2C_WRITE(rsf, RESTARTV_EN_ADDR, 0x0004);
	ret |= I2C_WRITE(rsf, FUNCNUM_ADDR, 0x0001);
	ret |= I2C_WRITE(rsf, CTRL_ADDR, 0x0008);
#if 0
  char rbuf[14];
  I2C_BURST_READ(PLL_SYSLUT_CFG0_ADDR, rbuf, 14);
  for (int j = 0; j < 14; j++)
    printk(KERN_INFO "0x%x ", rbuf[j]);
#endif
	if (0 != ret) {
		printk(KERN_ERR "i2c write err!\n");
		goto i2c_wr_err;
	}

	start_time = ktime_get();
	while (!pll_running) {
		I2C_READ(rsf, CMC_ADDR, &cmc_val);
		if (cmc_val & 0x0002)
			pll_running = true;

		if ((ktime_to_ms(ktime_sub(ktime_get(), start_time))) > 1000) {
			printk(KERN_ERR
			       "PLL power up failed due to timeout error--cmc_val(0x%x)\n",
			       cmc_val);
			return -1;
		}
	}

	printk(KERN_INFO "PLL power up done\n");

	return 0;

i2c_wr_err:
	return ret;
}

static int _config_spi(RX_SPI_FH *rsf)
{
	int ret = -1;

	ret = I2C_WRITE(rsf, SPICFG_ADDR, SPICFG_VAL);
	ret |= I2C_WRITE(rsf, SPIWRADDR_ADDR, SPIWRADDR_VAL);
	ret |= I2C_WRITE(rsf, SPIRADDR_ADDR, SPIRADDR_VAL);
	/*add new sensor reg config*/
	ret |= I2C_WRITE(rsf, 0xA08D, 0x1102); // enable manual overwrite
	ret |= I2C_WRITE(rsf, 0xA09B, 0x00FF); // write SPISIZE0
	ret |= I2C_WRITE(rsf, 0xA09C, 0xFFFF); // write SPISIZE1
	if (0 != ret)
		printk(KERN_ERR "config_SPI err!\n");
	return ret;
}

static int _setup_spi(RX_SPI_FH *rsf)
{
	int ret;

	ret = _pll_power_up(rsf);
	ret |= _config_spi(rsf);

	if (ret)
		printk(KERN_ERR "_setup_spi err!\n");
	else {
		rsf->spi_setup_done = true;
		printk(KERN_INFO "SPI setup done!\n");
	}
	return ret;
}

int rx_spi_flash_init(RX_SPI_FH *rsf, unsigned int f_ref)
{
	int ret = -1;
	uint16_t ID_REG = 0xA0A4;
	uint16_t id = 0;

	if (NULL == rsf) {
		printk(KERN_ERR "rsf is null!\n");
		return -1;
	}

	rsf->f_ref = f_ref;
	rsf->spi_setup_done = false;

	/*check who am i*/
	I2C_READ(rsf, ID_REG, &id);

	printk(KERN_INFO "SENSOR ID is 0x%x!\n", id);

	ret = _setup_spi(rsf);
	if (0 != ret) {
		printk(KERN_ERR "can't _setup_spi check the i2c_fd(%d)!\n",
		       ret);
	}
	return ret;
}

void rx_spi_flash_deinit(RX_SPI_FH *rsf)
{
}

static void _flash_write_enable(RX_SPI_FH *rsf)
{
	int ret = -1;
	// write enable command to SPI Flash
	ret = I2C_WRITE(rsf, SPIWRADDR_VAL, 0x0600);
	ret |= I2C_WRITE(rsf, SPILEN_ADDR, 0x0000);
	ret |= I2C_WRITE(rsf, SPITRIG_ADDR, 0x0002);
	if (ret)
		printk(KERN_ERR "i2c write err!\n");
	ret = _spi_command_finished(rsf);
	if (ret) {
		printk(KERN_ERR "_spi_command_finished err!\n");
	}
}

static int _spi_command_finished(RX_SPI_FH *rsf)
{
	ktime_t start_time;
	int ready = 0;
	uint16_t spistatus_val;
	int ret = -1;

	start_time = ktime_get();
	while (!ready) {
		ret = I2C_READ(rsf, SPISTATUS_ADDR, &spistatus_val);
		if (ret < 0) {
			printk(KERN_ERR "i2c read err!\n");
			return -1;
		}

		// printk(KERN_INFO "spistatus_val = 0x%x!\n", spistatus_val);
		if (spistatus_val & 0x0002) {
			printk(KERN_ERR
			       "spi_command_finished - SPI Error (SPISTATUS = 0x%04X)\n",
			       spistatus_val);
			return -3;
		}

		if (spistatus_val & 0x0001) {
			return 0;
		}

		if ((ktime_to_ms(ktime_sub(ktime_get(), start_time))) > 2000) {
			printk(KERN_ERR
			       "spi_command_finished - timeout_error (SPISTATUS = 0x%04X)\n",
			       spistatus_val);
			return -2;
		}
	}
	return 0;
}

static bool _is_flash_busy(RX_SPI_FH *rsf)
{
	int ret = -1;
	uint16_t write_buffer_addr = SPIWRADDR_VAL;
	uint16_t read_buffer_addr = SPIRADDR_VAL;
	uint16_t value;
	uint8_t spi_status1_val;

	if (!rsf->spi_setup_done) {
		printk(KERN_INFO "Re-setup of SPI necessary\n");
		_setup_spi(rsf);
	}
	// send command to get status1 regsiter from flash
	ret = I2C_WRITE(rsf, write_buffer_addr, 0x0500);
	ret |= I2C_WRITE(rsf, SPILEN_ADDR, 0x2001);
	// init and execute SPI Commands
	ret |= I2C_WRITE(rsf, SPITRIG_ADDR, 0x0002);
	if (ret) {
		printk(KERN_ERR "i2c write err!\n");
		return false;
	}
	// wait until transmission is finished
	_spi_command_finished(rsf);
	// read back status register1 from spi flash
	ret = I2C_READ(rsf, read_buffer_addr, &value);
	if (ret < 0) {
		printk(KERN_ERR "i2c read err!\n");
		return false;
	}

	spi_status1_val = (value & 0xFF00) >> 8;

	// printk(KERN_INFO "(S0 ~ S7)spi flash status_val = 0x%02x!\n", spi_status1_val);

	// check if spi flash is still busy executing the command
	if (spi_status1_val & 0x01)
		return true;
	else
		return false;
}

static int flash_read(RX_SPI_FH *rsf, uint32_t start_addr,
		      uint32_t num_of_bytes, uint8_t *buf)
{
	// int ret = -1;
	bool reading_finished = false;
	int read_bytes;
	// int i = 0;

	// check if spi setup was done before
	if (!rsf->spi_setup_done) {
		printk(KERN_INFO "Re-setup of SPI necessary\n");
		_setup_spi(rsf);
	}

	// printk(KERN_INFO "number of bytes(%d)from address 0x%06X\n", num_of_bytes,
	// start_addr);

	while (!reading_finished) {
		//printk(KERN_INFO "read %d\n", i++);
		if (num_of_bytes > 508) {
			read_bytes =
				_read_single_buffer(rsf, start_addr, 508, buf);
			if (read_bytes)
				return -1;

			buf += 508;
			num_of_bytes -= 508;
			start_addr += 0x1FC; // 508
		} else {
			read_bytes = _read_single_buffer(rsf, start_addr,
							 num_of_bytes, buf);
			if (read_bytes)
				return -2;

			reading_finished = true;
		}
	}
	return 0;
}

static int _read_single_buffer(RX_SPI_FH *rsf, uint32_t start_address,
			       uint32_t num_of_bytes, uint8_t *buf)
{
	uint16_t write_buffer_addr = SPIWRADDR_VAL;
	uint16_t read_buffer_addr = SPIRADDR_VAL;
	uint16_t upper_start_address;
	uint16_t lower_start_address;
	int ret = -1;
	int num_of_words;
	uint16_t output_words[256] = { 0 };

	// check if spi setup was done before
	if (!rsf->spi_setup_done) {
		printk(KERN_INFO "Re-setup of SPI necessary\n");
		_setup_spi(rsf);
	}

	if (num_of_bytes > 508) {
		printk(KERN_ERR
		       "number of Bytes given (%d) exceeds limit (max. 508 Bytes)\n",
		       num_of_bytes);
		return -1;
	}

	upper_start_address = (start_address & 0xFF0000) >> 16;
	lower_start_address = start_address & 0x00FFFF;
	// first fill up write buffer with read command and adress from where to read
	// read SPI command (0x03)/ upper SPI Address bits from where to read 0x00
	ret = I2C_WRITE(rsf, write_buffer_addr, (0x0300 + upper_start_address));
	// lower SPI Address bits from where to read
	ret |= I2C_WRITE(rsf, write_buffer_addr + 1, lower_start_address);
	// enable SDI / specify num of bytes to read
	ret |= I2C_WRITE(rsf, SPILEN_ADDR, (0xE003 + num_of_bytes));
	// init and execute SPI Commands
	ret |= I2C_WRITE(rsf, SPITRIG_ADDR, 0x0002);
	if (ret) {
		printk(KERN_ERR "I2C_WRITE err!\n");
		return -1;
	}
	// wait until imager has finished transmission
	ret = _spi_command_finished(rsf);
	if (ret) {
		printk(KERN_ERR "_spi_command_finished err!\n");
		return -2;
	}
	// read data from read buffer
	num_of_words = (num_of_bytes % 2 == 0) ? num_of_bytes / 2 :
						       num_of_bytes / 2 + 1;

	//printk(KERN_INFO "num_of_words: %d\n", num_of_words);

	ret = I2C_BURST_READ(rsf, read_buffer_addr, (uint16_t *)output_words,
			     num_of_words);
	if (ret < 0) {
		printk(KERN_ERR "ret = %d!!!!!!!!!!!!!!!!!!!!!!\n", ret);
		return -3;
	}
	/*{
		uint8_t *pbuf = (uint8_t *)output_words;
		int i;
		for (i = 0;i < num_of_bytes;i++){
			printk(KERN_INFO "%d=0x%x ", i, pbuf[i]);
		}
		printk(KERN_INFO "zzzzzzzzqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq\n");
	}*/
	words_to_bytes(output_words, buf, num_of_bytes);
	return 0;
}

static int erase_page(RX_SPI_FH *rsf, uint32_t start_address)
{
	uint32_t page_size = 0x000100;
	uint16_t write_buffer_addr = SPIWRADDR_VAL;
	uint16_t upper_start_address = (start_address & 0xFF0000) >> 16;
	uint16_t lower_start_address = start_address & 0x00FFFF;
	int ret = -1;
	ktime_t start_time;
	bool busy = false;

	// check if spi setup was done before
	if (!rsf->spi_setup_done) {
		printk(KERN_INFO "Re-setup of SPI necessary\n");
		_setup_spi(rsf);
	}

	if (start_address % page_size)
		printk(KERN_ERR
		       "SPI erase page - start address(0x%06X) is invalid! (Address must be "
		       "a multiple of "
		       "0x000100)\n",
		       start_address);
	// write enable

	_flash_write_enable(rsf);

	// erase page
	// Page Erase SPI command (0x81)/ upper SPI Address bits where to erase
	ret = I2C_WRITE(rsf, write_buffer_addr, 0x8100 + upper_start_address);
	// lower SPI Address bits of sector that should be erased
	ret |= I2C_WRITE(rsf, write_buffer_addr + 1, lower_start_address);
	ret |= I2C_WRITE(rsf, SPILEN_ADDR, 0x0003);
	ret |= I2C_WRITE(rsf, SPITRIG_ADDR, 0x0002);
	if (ret)
		printk(KERN_ERR "i2c write err!\n");
	// wait for imager to execute command
	ret = _spi_command_finished(rsf);
	if (ret) {
		printk(KERN_ERR "_spi_command_finished error!\n");
		return -2;
	}

	// wait until SPI has finished operation and is ready
	start_time = ktime_get();
	busy = _is_flash_busy(rsf);
	while (busy) {
		busy = _is_flash_busy(rsf);
		if ((ktime_to_ms(ktime_sub(ktime_get(), start_time))) > 2000) {
			printk(KERN_ERR "wait flash busy timeout_error\n");
			return -3;
		}
	}

	return ret;
}

static int _write_single_page(RX_SPI_FH *rsf, uint32_t page_address,
			      uint8_t *data_bytes, uint32_t num_of_bytes)
{
	//uint16_t output_words[129] = {0};
	uint8_t word_len = 0;
	uint16_t write_buffer_addr = SPIWRADDR_VAL;
	uint16_t upper_start_address = (page_address & 0xFF0000) >> 16;
	uint16_t lower_start_address = page_address & 0x00FFFF;
	int ret = -1;
	ktime_t start_time;
	uint16_t check_buf[128];
	bool busy = false;
	// check if spi setup was done before
	if (!rsf->spi_setup_done) {
		printk(KERN_INFO "Re-setup of SPI necessary\n");
		_setup_spi(rsf);
	}

	//printk(KERN_INFO "----number of bytes(%d)from address 0x%06X\n", num_of_bytes, page_address);

	if (num_of_bytes > 256) {
		printk(KERN_ERR
		       "num_of_bytes(%d) exceeds limit max.256 Bytes\n",
		       num_of_bytes);
	}

	// bytes_to_words(data_bytes, output_words + 1, num_of_bytes);
	//memcpy(output_words + 1, data_bytes, num_of_bytes);
	word_len = (num_of_bytes % 2 == 0) ? num_of_bytes / 2 :
						   num_of_bytes / 2 + 1;

	_flash_write_enable(rsf);
	// write page
	// Page Program SPI command (0x02)/ upper SPI Address bits where to write
	ret = I2C_WRITE(rsf, write_buffer_addr, 0x0200 + upper_start_address);
	if (ret)
		printk(KERN_ERR "i2c write err,ret=%d!\n", ret);
	// lower SPI Address bits from where to read
	ret = I2C_WRITE(rsf, write_buffer_addr + 1, lower_start_address);
	if (ret)
		printk(KERN_ERR "i2c write err,ret=%d!\n", ret);
	// write data to write buffer

	//output_words[0] =
	//    ((write_buffer_addr + 2) >> 8) | (((write_buffer_addr + 2) & 0xff) << 8);
	ret = I2C_BURST_WRITE(rsf, write_buffer_addr + 2, data_bytes,
			      num_of_bytes);
	// printk(KERN_INFO "I2C_BURST_WRITE ok,ret=%d!, data=0x%04x\n", ret, output_words[1]);

	if (ret)
		printk(KERN_ERR "i2c write err,ret=%d!\n", ret);
	// specify num of bytes to write to flash
	ret = I2C_WRITE(rsf, SPILEN_ADDR, 0x0003 + num_of_bytes);
	if (ret)
		printk(KERN_ERR "i2c write err,ret=%d!\n", ret);
	// init and execute SPI Commands
	ret = I2C_WRITE(rsf, SPITRIG_ADDR, 0x0002);
	if (ret)
		printk(KERN_ERR "i2c write err,ret=%d!\n", ret);

	// wait for imager to execute command
	// printk(KERN_INFO "wait _spi_command_finished!\n");
	ret = _spi_command_finished(rsf);
	if (ret) {
		printk(KERN_ERR "wait _spi_command_finished error!\n");
		return -9;
	}

	// printk(KERN_INFO "wait _is_flash_busy!\n");
	start_time = ktime_get();
	busy = _is_flash_busy(rsf);
	while (busy) {
		busy = _is_flash_busy(rsf);
		if ((ktime_to_ms(ktime_sub(ktime_get(), start_time))) > 1000) {
			printk(KERN_ERR "wait flash not busy time out!\n");
			return -10;
		}
	}
#if DEBUG
	{
		uint8_t *tmp = data_bytes;
		int i = 0;
		for (i = 0; i < num_of_bytes; i++) {
			printk(KERN_INFO "0x%x ", tmp[i]);
		}
		printk(KERN_INFO
		       "\neeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\n");
	}
#endif
	_read_single_buffer(rsf, page_address, num_of_bytes,
			    (uint8_t *)check_buf);
	ret = memcmp(check_buf, data_bytes, num_of_bytes);
	if (ret) {
		printk(KERN_INFO "_write_single_page check err!\n");
	}
#if DEBUG
	{
		uint8_t *pbuf = (uint8_t *)check_buf;
		int i = 0;
		for (i = 0; i < num_of_bytes; i++) {
			printk(KERN_INFO "0x%x ", pbuf[i]);
		}
		printk(KERN_INFO "\n11111111111\n");
	}
#endif
	return ret;
}

// Automatically generated CRC function
// polynomial: 0x104C11DB7
static unsigned int update_crc32(unsigned int crc, const unsigned char *data,
				 size_t len)
{
	static const unsigned int table[256] = {
		0x00000000U, 0x04C11DB7U, 0x09823B6EU, 0x0D4326D9U, 0x130476DCU,
		0x17C56B6BU, 0x1A864DB2U, 0x1E475005U, 0x2608EDB8U, 0x22C9F00FU,
		0x2F8AD6D6U, 0x2B4BCB61U, 0x350C9B64U, 0x31CD86D3U, 0x3C8EA00AU,
		0x384FBDBDU, 0x4C11DB70U, 0x48D0C6C7U, 0x4593E01EU, 0x4152FDA9U,
		0x5F15ADACU, 0x5BD4B01BU, 0x569796C2U, 0x52568B75U, 0x6A1936C8U,
		0x6ED82B7FU, 0x639B0DA6U, 0x675A1011U, 0x791D4014U, 0x7DDC5DA3U,
		0x709F7B7AU, 0x745E66CDU, 0x9823B6E0U, 0x9CE2AB57U, 0x91A18D8EU,
		0x95609039U, 0x8B27C03CU, 0x8FE6DD8BU, 0x82A5FB52U, 0x8664E6E5U,
		0xBE2B5B58U, 0xBAEA46EFU, 0xB7A96036U, 0xB3687D81U, 0xAD2F2D84U,
		0xA9EE3033U, 0xA4AD16EAU, 0xA06C0B5DU, 0xD4326D90U, 0xD0F37027U,
		0xDDB056FEU, 0xD9714B49U, 0xC7361B4CU, 0xC3F706FBU, 0xCEB42022U,
		0xCA753D95U, 0xF23A8028U, 0xF6FB9D9FU, 0xFBB8BB46U, 0xFF79A6F1U,
		0xE13EF6F4U, 0xE5FFEB43U, 0xE8BCCD9AU, 0xEC7DD02DU, 0x34867077U,
		0x30476DC0U, 0x3D044B19U, 0x39C556AEU, 0x278206ABU, 0x23431B1CU,
		0x2E003DC5U, 0x2AC12072U, 0x128E9DCFU, 0x164F8078U, 0x1B0CA6A1U,
		0x1FCDBB16U, 0x018AEB13U, 0x054BF6A4U, 0x0808D07DU, 0x0CC9CDCAU,
		0x7897AB07U, 0x7C56B6B0U, 0x71159069U, 0x75D48DDEU, 0x6B93DDDBU,
		0x6F52C06CU, 0x6211E6B5U, 0x66D0FB02U, 0x5E9F46BFU, 0x5A5E5B08U,
		0x571D7DD1U, 0x53DC6066U, 0x4D9B3063U, 0x495A2DD4U, 0x44190B0DU,
		0x40D816BAU, 0xACA5C697U, 0xA864DB20U, 0xA527FDF9U, 0xA1E6E04EU,
		0xBFA1B04BU, 0xBB60ADFCU, 0xB6238B25U, 0xB2E29692U, 0x8AAD2B2FU,
		0x8E6C3698U, 0x832F1041U, 0x87EE0DF6U, 0x99A95DF3U, 0x9D684044U,
		0x902B669DU, 0x94EA7B2AU, 0xE0B41DE7U, 0xE4750050U, 0xE9362689U,
		0xEDF73B3EU, 0xF3B06B3BU, 0xF771768CU, 0xFA325055U, 0xFEF34DE2U,
		0xC6BCF05FU, 0xC27DEDE8U, 0xCF3ECB31U, 0xCBFFD686U, 0xD5B88683U,
		0xD1799B34U, 0xDC3ABDEDU, 0xD8FBA05AU, 0x690CE0EEU, 0x6DCDFD59U,
		0x608EDB80U, 0x644FC637U, 0x7A089632U, 0x7EC98B85U, 0x738AAD5CU,
		0x774BB0EBU, 0x4F040D56U, 0x4BC510E1U, 0x46863638U, 0x42472B8FU,
		0x5C007B8AU, 0x58C1663DU, 0x558240E4U, 0x51435D53U, 0x251D3B9EU,
		0x21DC2629U, 0x2C9F00F0U, 0x285E1D47U, 0x36194D42U, 0x32D850F5U,
		0x3F9B762CU, 0x3B5A6B9BU, 0x0315D626U, 0x07D4CB91U, 0x0A97ED48U,
		0x0E56F0FFU, 0x1011A0FAU, 0x14D0BD4DU, 0x19939B94U, 0x1D528623U,
		0xF12F560EU, 0xF5EE4BB9U, 0xF8AD6D60U, 0xFC6C70D7U, 0xE22B20D2U,
		0xE6EA3D65U, 0xEBA91BBCU, 0xEF68060BU, 0xD727BBB6U, 0xD3E6A601U,
		0xDEA580D8U, 0xDA649D6FU, 0xC423CD6AU, 0xC0E2D0DDU, 0xCDA1F604U,
		0xC960EBB3U, 0xBD3E8D7EU, 0xB9FF90C9U, 0xB4BCB610U, 0xB07DABA7U,
		0xAE3AFBA2U, 0xAAFBE615U, 0xA7B8C0CCU, 0xA379DD7BU, 0x9B3660C6U,
		0x9FF77D71U, 0x92B45BA8U, 0x9675461FU, 0x8832161AU, 0x8CF30BADU,
		0x81B02D74U, 0x857130C3U, 0x5D8A9099U, 0x594B8D2EU, 0x5408ABF7U,
		0x50C9B640U, 0x4E8EE645U, 0x4A4FFBF2U, 0x470CDD2BU, 0x43CDC09CU,
		0x7B827D21U, 0x7F436096U, 0x7200464FU, 0x76C15BF8U, 0x68860BFDU,
		0x6C47164AU, 0x61043093U, 0x65C52D24U, 0x119B4BE9U, 0x155A565EU,
		0x18197087U, 0x1CD86D30U, 0x029F3D35U, 0x065E2082U, 0x0B1D065BU,
		0x0FDC1BECU, 0x3793A651U, 0x3352BBE6U, 0x3E119D3FU, 0x3AD08088U,
		0x2497D08DU, 0x2056CD3AU, 0x2D15EBE3U, 0x29D4F654U, 0xC5A92679U,
		0xC1683BCEU, 0xCC2B1D17U, 0xC8EA00A0U, 0xD6AD50A5U, 0xD26C4D12U,
		0xDF2F6BCBU, 0xDBEE767CU, 0xE3A1CBC1U, 0xE760D676U, 0xEA23F0AFU,
		0xEEE2ED18U, 0xF0A5BD1DU, 0xF464A0AAU, 0xF9278673U, 0xFDE69BC4U,
		0x89B8FD09U, 0x8D79E0BEU, 0x803AC667U, 0x84FBDBD0U, 0x9ABC8BD5U,
		0x9E7D9662U, 0x933EB0BBU, 0x97FFAD0CU, 0xAFB010B1U, 0xAB710D06U,
		0xA6322BDFU, 0xA2F33668U, 0xBCB4666DU, 0xB8757BDAU, 0xB5365D03U,
		0xB1F740B4U,
	};

	while (len > 0) {
		crc = table[*data ^ ((crc >> 24) & 0xff)] ^ (crc << 8);
		data++;
		len--;
		// printk(KERN_INFO "the crc is 0x%x\n", crc);
	}
	return crc;
}

static unsigned int crc32(const unsigned char *buf, size_t len,
			  unsigned int initdata)
{
	uint32_t data = update_crc32(initdata, buf, len) ^ 0xffffffff;
	// printk(KERN_INFO "the crc is 0x%x\n", data);
	return data;
}

int write_sn(struct v4l2_subdev *sd, char sn[], int len)
{
	int ret = -1;
	char buf[256];
	unsigned int *p;

	RX_SPI_FH rsf;
	rsf.sd = sd;
	ret = rx_spi_flash_init(&rsf, 24000000);
	if (ret) {
		printk(KERN_ERR "rx_spi_flash_init failed!\n");
		ret = -1;
		return ret;
	}
	printk(KERN_INFO "start write sn=%s, len=%d\n", sn, len);

	//_read_flashid(rsf);

	// printk(KERN_INFO "erase_page start spi_addr(0x%4x)##########################!\n",
	// SN_HEAD_ADDR);
	ret = erase_page(&rsf, SN_HEAD_ADDR);
	if (ret) {
		printk(KERN_ERR "erase_page error, ret = %d\n", ret);
		return -2;
	}
	// printk(KERN_INFO "erase_page end###############################################!\n");

	memset(buf, 0, 256);
	p = (unsigned int *)buf;
	*p = len;
	*(p + 1) = crc32(sn, len, 0xffffffff);
	memcpy(p + 2, sn, len);
	ret = _write_single_page(&rsf, SN_HEAD_ADDR, buf, len + 8);
	if (ret) {
		printk(KERN_ERR "_write_single_page is error, ret=%d!\n", ret);
		ret = -3;
		return ret;
	}

	printk(KERN_INFO "_write sn is ok!\n");
	return 0;
}

int read_sn(struct v4l2_subdev *sd, char *sn)
{
	uint8_t buf[256] = { 0 };
	int ret;
	unsigned int crc;
	unsigned int sn_len;
	unsigned int *p = (unsigned int *)buf;
	RX_SPI_FH rsf;
	rsf.sd = sd;

	ret = rx_spi_flash_init(&rsf, 24000000);
	if (ret) {
		printk(KERN_ERR "spi flash init error.\n");
		return -1;
	}
	ret = _read_single_buffer(&rsf, SN_HEAD_ADDR, 256, buf);
	sn_len = *p;
	if (sn_len > 128) {
		printk(KERN_ERR "sn len is error! len = %d\n", sn_len);
		return -4;
	}

	crc = crc32(buf + 8, *p, 0xffffffff);
	if (crc != *(p + 1)) {
		printk(KERN_ERR "sn crc check is failed!\n");
		ret = -2;
		return ret;
	} else {
		strncpy(sn, buf + 8, sn_len);
	}
	printk(KERN_INFO "sn crc check is ok!sn=%s,\n", sn);
	return 0;
}

int read_calib_info(struct v4l2_subdev *sd, char *calib_info, int *len,
		    int *crc32_value)
{
	int ret = -1;
	uint32_t file_len = 0;
	uint32_t file_crc = 0;
	uint32_t file_crc_new = 0xFFFFFFFF;

	RX_SPI_FH rsf;
	rsf.sd = sd;
	ret = rx_spi_flash_init(&rsf, 24000000);
	if (ret) {
		return -9;
	}

	/*1.file_length_get*/
	ret = flash_read(&rsf, CALIB_FILE_HEAD_ADDR, 4, (uint8_t *)&file_len);
	printk(KERN_INFO "file len: 0x%x!\n", file_len);
	if ((file_len > CALIB_INFO_MAX_LEN) || (file_len < 10*1024)) {
		printk(KERN_INFO "file len error: 0x%x!\n", file_len);
		ret = -1;
		return ret;
	}

	ret = flash_read(&rsf, CALIB_FILE_HEAD_ADDR + 4, 4,
			 (uint8_t *)&file_crc);
	//printk(KERN_INFO "file org crc: 0x%x!\n", file_crc);

	ret = flash_read(&rsf, CALIB_FILE_HEAD_ADDR + 256, file_len,
			 (uint8_t *)calib_info);

	file_crc_new = crc32(calib_info, file_len, 0xffffffff);

	if (file_crc_new != file_crc) {
		printk(KERN_INFO
		       "file crc org: 0x%x-file crc new: 0x%x, file len=%d\n",
		       file_crc, file_crc_new, file_len);
		ret = -3;
		return ret;
	}
	*len = file_len;
	*crc32_value = file_crc;
	printk(KERN_INFO "read clib ok.\n");
	return 0;
}

int read_device_info(struct v4l2_subdev *sd, uint8_t* info) {
	uint8_t buf[256] = {0};
	int ret;
	unsigned int device_info_len;
	unsigned int crc;
	unsigned int* p = (unsigned int*)buf;
	RX_SPI_FH rsf;
	rsf.sd = sd;

	ret = rx_spi_flash_init(&rsf, 24000000);
	if (ret) {
		printk(KERN_ERR "spi flash init error.\n");
		return -1;
	}
	ret = _read_single_buffer(&rsf, DEVICE_INFO_HEAD_ADDR, 256, buf);
	device_info_len = *p;
	if (device_info_len > 244) {
		printk(KERN_ERR "device info len is error! len = %d\n", device_info_len);
		ret = -1;
		goto failed;
	}

	crc = crc32(buf + 8, *p, 0xffffffff);
	if (crc != *(p + 1)) {
		printk(KERN_ERR "device info crc check is failed!\n");
		ret = -2;
		goto failed;
	} else {
		memcpy(info, buf + 8, device_info_len);
	}
	printk(KERN_INFO "device info crc check is ok!\n");
	return 0;
failed:
	return ret;
}

